use multi_support_app::{
    user_server::User, CreateReply, CreateRequest, DeleteReply, DeleteRequest, GetReply,
    GetRequest, ListReply, ListRequest, UserInfo,
};

use crate::{
    facade::{builder::Builder, user::UserFacade},
    payload::user::UserCreatePayload,
    provider::user::UserProvider,
    utils::tool,
};

#[derive(Debug)]
pub struct UserService;

#[tonic::async_trait]
impl User for UserService {
    async fn list(
        &self,
        request: tonic::Request<ListRequest>,
    ) -> Result<tonic::Response<ListReply>, tonic::Status> {
        let page = tool::page(&request.get_ref().page);
        let pagesize = tool::pagesize(&request.get_ref().pagesize);
        let user_list_ret = UserProvider::builder().fetch(page, pagesize).await;
        if user_list_ret.is_err() {
            return Err(tonic::Status::new(
                tonic::Code::Ok,
                user_list_ret.err().unwrap().to_string(),
            ));
        }
        let user_list = user_list_ret.unwrap();
        let mut list: Vec<UserInfo> = Vec::new();
        let mut size = 0;
        for i in user_list.iter() {
            list.push(UserInfo {
                id: i.id,
                user_id: i.user_id.clone(),
                username: i.username.clone(),
                user_intro: i.user_intro.clone(),
                created_at: i.created_at.to_string(),
            });
            size = size + 1;
        }
        let reply = ListReply {
            page: page,
            pagesize: pagesize,
            size: size,
            list: list,
        };
        Ok(tonic::Response::new(reply))
    }
    async fn get(
        &self,
        request: tonic::Request<GetRequest>,
    ) -> Result<tonic::Response<GetReply>, tonic::Status> {
        let user_id = request.get_ref().user_id.to_string();
        let user_ret = UserProvider::builder().get_by_user_id(user_id).await;
        if user_ret.is_err() {
            return Err(tonic::Status::new(
                tonic::Code::Ok,
                user_ret.err().unwrap().to_string(),
            ));
        }
        let user_opt = user_ret.unwrap();
        let mut reply = GetReply { user_info: None };
        if user_opt.is_none() {
            return Ok(tonic::Response::new(reply));
        }
        let user = user_opt.unwrap();
        let user_info = UserInfo {
            id: user.id,
            user_id: user.user_id,
            username: user.username,
            user_intro: user.user_intro,
            created_at: user.created_at.to_string(),
        };
        reply.user_info = Some(user_info);
        Ok(tonic::Response::new(reply))
    }
    async fn create(
        &self,
        request: tonic::Request<CreateRequest>,
    ) -> Result<tonic::Response<CreateReply>, tonic::Status> {
        let payload = UserCreatePayload {
            username: request.get_ref().username.to_string(),
            password: request.get_ref().password.to_string(),
            user_intro: request.get_ref().user_intro.to_string(),
        };
        let create_ret = UserProvider::builder().create(payload).await;
        if create_ret.is_err() {
            return Err(tonic::Status::new(
                tonic::Code::Ok,
                create_ret.err().unwrap().to_string(),
            ));
        }
        let user = create_ret.unwrap();
        let user_info = UserInfo {
            id: user.id,
            user_id: user.user_id,
            username: user.username,
            user_intro: user.user_intro,
            created_at: user.created_at.to_string(),
        };
        let reply = CreateReply {
            user_info: Some(user_info),
        };
        Ok(tonic::Response::new(reply))
    }
    async fn delete(
        &self,
        request: tonic::Request<DeleteRequest>,
    ) -> Result<tonic::Response<DeleteReply>, tonic::Status> {
        let user_id = &request.get_ref().user_id;
        let user_ret = UserProvider::builder()
            .delete_by_user_id(user_id.to_string())
            .await;
        if user_ret.is_err() {
            return Err(tonic::Status::new(
                tonic::Code::Ok,
                user_ret.err().unwrap().to_string(),
            ));
        }
        let user_opt = user_ret.unwrap();
        let mut reply = DeleteReply { user_info: None };
        if user_opt.is_none() {
            return Ok(tonic::Response::new(reply));
        }
        let user = user_opt.unwrap();
        let user_info = UserInfo {
            id: user.id,
            user_id: user.user_id,
            username: user.username,
            user_intro: user.user_intro,
            created_at: user.created_at.to_string(),
        };
        reply.user_info = Some(user_info);
        Ok(tonic::Response::new(reply))
    }
}
